home *** CD-ROM | disk | FTP | other *** search
- /* gf_input.c: read objects from one GF file.
-
- Copyright (C) 1992 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-
- #include "config.h"
-
- #include "file-input.h"
- #include "gf.h"
- #include "scaled-num.h"
-
- #include "gf_opcodes.h"
-
-
- /* If true, print out what we read. */
- static boolean tracing_gf_input = false;
-
-
- /* These identify the file we're reading, for our own use. */
- static string gf_input_filename;
- static FILE *gf_input_file;
-
-
- /* Low-level input. These macros call the corresponding routines in
- kbase, using the static variables for the input file and filename. */
-
- #define GF_FTELL() xftell (gf_input_file, gf_input_filename)
- #define GF_FSEEK(offset, from_where) \
- xfseek (gf_input_file, offset, from_where, gf_input_filename)
- #define GF_GET_BYTE() get_byte (gf_input_file, gf_input_filename)
- #define GF_GET_PREVIOUS() get_previous_byte (gf_input_file, gf_input_filename)
- #define GF_GET_TWO() get_two (gf_input_file, gf_input_filename)
- #define GF_GET_FOUR() get_four (gf_input_file, gf_input_filename)
- #define GF_GET_SIGNED_FOUR() \
- get_signed_four (gf_input_file, gf_input_filename)
- #define GF_GET_PREVIOUS_FOUR() \
- get_previous_four (gf_input_file, gf_input_filename)
- #define GF_MATCH_BYTE(expected) \
- match_byte (expected, gf_input_file, gf_input_filename)
-
- static void get_specials (byte_count_type special_ptr);
- static string gf_get_string (unsigned string_length);
- static four_bytes gf_get_three (void);
-
-
- /* We have occasion to refer to the postamble when reading the characters,
- so we keep a copy for ourselves. */
- static gf_postamble_type *private_postamble;
-
- /* This reads into `private_postamble'. */
- static void get_postamble (void);
-
- static void get_locators (void);
-
-
- /* Pointers to the characters we have read. */
- static gf_char_type *char_list[MAX_CHARCODE + 1];
-
-
- /* Subroutines for reading a character. */
- static void get_full_boc (gf_char_type *);
- static void get_abbreviated_boc (gf_char_type *);
- static void get_character_bitmap (gf_char_type *);
- static void get_postamble_info (gf_char_type *);
- static void deblank (gf_char_type *);
-
- /* Subroutines for reading the bitmap. */
- static void get_paint (coordinate_type *, boolean *, one_byte, gf_char_type *);
- static void get_skip (coordinate_type *, boolean *, one_byte, gf_char_type *);
- static void get_new_row
- (coordinate_type *, boolean *, one_byte, gf_char_type *);
-
- /* For handling raw characters. */
- static void append_byte (raw_char_type *, one_byte);
- static void append_n_bytes (raw_char_type *, four_bytes, one_byte *);
- static raw_char_type new_raw_gf_char (gf_char_locator_type);
-
- /* Start reading FILENAME. Return false if it can't be opened. */
-
- boolean
- gf_open_input_file (string filename)
- {
- if (gf_input_file != NULL)
- FATAL2 ("gf_open_input_file: Attempt to open `%s', but `%s' is
- already open", filename, gf_input_filename);
-
- gf_input_filename = filename;
- gf_input_file = fopen (filename, "r");
-
- return gf_input_file != NULL;
- }
-
-
- void
- gf_close_input_file ()
- {
- unsigned code;
-
- assert (gf_input_file != NULL);
-
- xfclose (gf_input_file, gf_input_filename);
-
- gf_input_filename = NULL;
- gf_input_file = NULL;
- private_postamble = NULL;
-
- for (code = 0; code <= MAX_CHARCODE; code++)
- char_list[code] = NULL;
- }
-
- /* The only interesting thing in the preamble, either to the user or to
- us, is the comment.
-
- It is wrong to save and restore the position in the gf file, since
- this routine is primarily useful if the user intends to use
- `gf_get_next_char', i.e., read the characters in the order they
- appear. In that case, the user has to read the preamble first. */
-
- string
- gf_get_preamble ()
- {
- one_byte comment_length;
- string answer;
-
- assert (gf_input_file != NULL);
-
- GF_MATCH_BYTE (PRE);
- GF_MATCH_BYTE (GF_ID);
-
- comment_length = GF_GET_BYTE ();
- answer = gf_get_string (comment_length);
-
- return answer;
- }
-
- /* Reading the postamble. This is the user-level call. We make no
- assumptions about the current position of the file pointer. */
-
- gf_postamble_type
- gf_get_postamble ()
- {
- one_byte b;
- byte_count_type old_pos, post_ptr;
- unsigned this_char;
-
- assert (gf_input_file != NULL);
-
- if (private_postamble != NULL) /* Previously read it? */
- return *private_postamble;
-
- old_pos = GF_FTELL ();
- GF_FSEEK (0, SEEK_END);
-
- /* If the input file is empty, give a better message than `Invalid
- argument' (because we are trying to seek before the beginning). */
- if (GF_FTELL () == 0)
- FATAL1 ("%s: empty file", gf_input_filename);
-
- do
- b = GF_GET_PREVIOUS ();
- while (b == GF_SIGNATURE);
-
- if (b != GF_ID)
- FATAL2 ("Expected GF id (%u), found %u", GF_ID, b);
-
- post_ptr = GF_GET_PREVIOUS_FOUR ();
-
- private_postamble = xmalloc (sizeof (gf_postamble_type));
-
- for (this_char = 0; this_char <= MAX_CHARCODE; this_char++)
- {
- GF_CHAR_LOC (*private_postamble, this_char).charcode
- = this_char;
- GF_CHAR_LOC (*private_postamble, this_char).char_pointer
- = NULL_BYTE_PTR;
- }
-
- GF_FSEEK (post_ptr, SEEK_SET);
- get_postamble (); /* Fills in `private_postamble'. */
-
- GF_FSEEK (old_pos, SEEK_SET);
- return *private_postamble;
- }
-
-
- /* Assume we are positioned at the beginning of the postamble. Fill in
- `private_postamble' with what we find. */
-
- static void
- get_postamble ()
- {
- GF_MATCH_BYTE (POST);
-
- (void) GF_GET_FOUR (); /* Ignore the special pointer. */
-
- GF_DESIGN_SIZE (*private_postamble) = GF_GET_FOUR ();
- GF_CHECKSUM (*private_postamble) = GF_GET_FOUR ();
-
- /* The resolution values are stored in the file as pixels per point,
- scaled by 2^16. */
- GF_H_RESOLUTION (*private_postamble) = GF_GET_FOUR ();
- GF_V_RESOLUTION (*private_postamble) = GF_GET_FOUR ();
-
- MIN_COL (GF_FONT_BB (*private_postamble)) = GF_GET_SIGNED_FOUR ();
- MAX_COL (GF_FONT_BB (*private_postamble)) = GF_GET_SIGNED_FOUR ();
- MIN_ROW (GF_FONT_BB (*private_postamble)) = GF_GET_SIGNED_FOUR ();
- MAX_ROW (GF_FONT_BB (*private_postamble)) = GF_GET_SIGNED_FOUR ();
-
- get_locators ();
- }
-
-
- /* We do not know in advance how many character locators exist, but we do
- place a maximum on it (contrary to what the GF format definition
- says), namely, MAX_CHARCODE. */
-
- static void
- get_locators ()
- {
- do
- {
- one_byte code;
- one_byte b = GF_GET_BYTE ();
-
- if (b == POST_POST)
- break;
-
- code = GF_GET_BYTE ();
-
- if (b == CHAR_LOC)
- {
- GF_CHAR_LOC (*private_postamble, code).h_escapement
- = scaled_to_real (GF_GET_FOUR ()) + .5;
- (void) GF_GET_FOUR (); /* Ignore vertical escapement. */
- }
- else if (b == CHAR_LOC0)
- GF_CHAR_LOC (*private_postamble, code).h_escapement = GF_GET_BYTE ();
- else
- FATAL1 ("Expected a char_loc command, not %u", b);
-
- GF_CHAR_LOC (*private_postamble, code).tfm_width = GF_GET_FOUR ();
- GF_CHAR_LOC (*private_postamble, code).char_pointer = GF_GET_FOUR ();
- }
- while (true);
- }
-
- /* Unlike `gf_get_next_char' (which comes next), this routine will get any
- character by its code. It is meant to be called by the user. We
- save all the characters we read in the static `char_list', to avoid
- going out to the file each time. */
-
- gf_char_type *
- gf_get_char (one_byte charcode)
- {
- gf_char_locator_type char_locator;
- byte_count_type char_pointer;
-
- if (char_list[charcode] != NULL)
- return char_list[charcode];
-
- (void) gf_get_postamble ();
- assert (private_postamble != NULL);
-
- char_locator = GF_CHAR_LOC (*private_postamble, charcode);
- char_pointer = char_locator.char_pointer;
-
- if (char_pointer != NULL_BYTE_PTR)
- {
- boolean found;
- byte_count_type old_pos = GF_FTELL ();
- GF_FSEEK (char_pointer, SEEK_SET);
-
- char_list[charcode] = xmalloc (sizeof (gf_char_type));
- *(char_list[charcode]) = gf_get_next_char (&found);
- assert (found);
-
- GF_FSEEK (old_pos, SEEK_SET);
- }
-
- return char_list[charcode];
- }
-
-
- /* This reads the character starting from the current position (but some
- specials might come first). */
-
- gf_char_type
- gf_get_next_char (boolean *found)
- {
- one_byte c;
- gf_char_type gf_char;
-
- get_specials (GF_FTELL ());
-
- c = GF_GET_BYTE ();
-
- if (c == BOC)
- get_full_boc (&gf_char);
-
- else if (c == BOC1)
- get_abbreviated_boc (&gf_char);
-
- else if (c == POST)
- {
- *found = false;
- return gf_char; /* We are returning garbage, but that's OK. */
- }
-
- else
- FATAL1 ("Expected a character (or the postamble), found %u", c);
-
- get_character_bitmap (&gf_char);
- get_postamble_info (&gf_char);
-
- deblank (&gf_char);
-
- *found = true;
- return gf_char;
- }
-
-
- /* If the back pointer actually points somewhere, this character is a
- ``residue'', and the font is probably too big. */
-
- static void
- get_full_boc (gf_char_type *gf_char)
- {
- signed_4_bytes back_pointer, charcode;
-
- charcode = GF_GET_SIGNED_FOUR ();
- if (charcode < 0 || charcode > MAX_CHARCODE)
- /* Someone is trying to use a font with character codes that are
- out of our range. */
- FATAL1 ("Character code %d out of range 0..255 in GF file (sorry)",
- charcode);
-
- GF_CHARCODE (*gf_char) = charcode;
-
- back_pointer = GF_GET_SIGNED_FOUR ();
- if (back_pointer != -1)
- WARNING2 ("Character %u has a non-null back pointer (to %d)",
- GF_CHARCODE (*gf_char), back_pointer);
-
- GF_CHAR_MIN_COL (*gf_char) = GF_GET_SIGNED_FOUR ();
- GF_CHAR_MAX_COL (*gf_char) = GF_GET_SIGNED_FOUR ();
- GF_CHAR_MIN_ROW (*gf_char) = GF_GET_SIGNED_FOUR ();
- GF_CHAR_MAX_ROW (*gf_char) = GF_GET_SIGNED_FOUR ();
- }
-
-
- static void
- get_abbreviated_boc (gf_char_type *gf_char)
- {
- one_byte col_delta, row_delta;
-
- GF_CHARCODE (*gf_char) = GF_GET_BYTE ();
-
- col_delta = GF_GET_BYTE ();
- GF_CHAR_MAX_COL (*gf_char) = GF_GET_BYTE ();
- GF_CHAR_MIN_COL (*gf_char) = GF_CHAR_MAX_COL (*gf_char) - col_delta;
-
- row_delta = GF_GET_BYTE ();
- GF_CHAR_MAX_ROW (*gf_char) = GF_GET_BYTE ();
- GF_CHAR_MIN_ROW (*gf_char) = GF_CHAR_MAX_ROW (*gf_char) - row_delta;
- }
-
-
- /* We also want to return the horizontal escapement (i.e., set width)
- and the TFM width as part of the character, although this information is
- not part of the boc..eoc, but rather the postamble. */
-
- static void
- get_postamble_info (gf_char_type *gf_char)
- {
- gf_char_locator_type char_locator;
-
- (void) gf_get_postamble (); /* Use `private_postamble'. */
- assert (private_postamble != NULL);
-
- char_locator = GF_CHAR_LOC (*private_postamble, GF_CHARCODE (*gf_char));
-
- GF_H_ESCAPEMENT (*gf_char) = char_locator.h_escapement;
- GF_TFM_WIDTH (*gf_char) = char_locator.tfm_width;
- }
-
-
- /* The GF format does not guarantee that the bounding box is the
- smallest possible, i.e., that the character bitmap does not have
- blank rows or columns at an edge. We want to remove such blanks. */
-
- static void
- deblank (gf_char_type *gf_char)
- {
- boolean all_white;
- bitmap_type gf_bitmap = GF_BITMAP (*gf_char);
- unsigned width = BITMAP_WIDTH (gf_bitmap),
- height = BITMAP_HEIGHT (gf_bitmap);
- unsigned white_on_left = 0, white_on_right = 0,
- white_on_top = 0, white_on_bottom = 0;
- int this_col, this_row; /* int in case GF_CHAR is zero pixels wide. */
-
- /* Let's start with blank columns at the left-hand side. */
- all_white = true;
- for (this_col = 0; this_col < width && all_white; this_col++)
- {
- for (this_row = 0; this_row < height && all_white; this_row++)
- {
- if (BITMAP_PIXEL (gf_bitmap, this_row, this_col) != 0)
- all_white = false;
- }
- if (all_white)
- white_on_left++;
- }
-
- /* Now let's check the right-hand side. */
- all_white = true;
- for (this_col = width - 1; this_col >= 0 && all_white; this_col--)
- {
- for (this_row = 0; this_row < height && all_white; this_row++)
- {
- if (BITMAP_PIXEL (gf_bitmap, this_row, this_col) != WHITE)
- all_white = false;
- }
- if (all_white)
- white_on_right++;
- }
-
- /* Check for all-white rows on top now. */
- all_white = true;
- for (this_row = 0; this_row < height && all_white; this_row++)
- {
- for (this_col = 0; this_col < width && all_white; this_col++)
- {
- if (BITMAP_PIXEL (gf_bitmap, this_row, this_col) != WHITE)
- all_white = false;
- }
- if (all_white)
- white_on_top++;
- }
-
- /* And, last, for all-white rows on the bottom. */
- all_white = true;
- for (this_row = height - 1; this_row >= 0 && all_white; this_row--)
- {
- for (this_col = 0; this_col < width && all_white; this_col++)
- {
- if (BITMAP_PIXEL (gf_bitmap, this_row, this_col) != WHITE)
- all_white = false;
- }
- if (all_white)
- white_on_bottom++;
- }
-
- /* If we have to remove columns at either the left or the right, we
- have to reallocate the memory, since much code depends on the fact
- that the bitmap is in contiguous memory. If we have to remove
- rows, we don't necessarily have to reallocate the memory, but we
- might as well, to save space. */
- if (white_on_left > 0 || white_on_right > 0
- || white_on_top > 0 || white_on_bottom > 0)
- {
- bitmap_type condensed;
-
- if (white_on_left + white_on_right > width)
- { /* The character was entirely blank. */
- BITMAP_WIDTH (condensed) = BITMAP_HEIGHT (condensed) = 0;
- GF_CHAR_MIN_COL (*gf_char) = GF_CHAR_MAX_COL (*gf_char)
- = GF_CHAR_MIN_ROW (*gf_char) = GF_CHAR_MAX_ROW (*gf_char) = 0;
- BITMAP_BITS (condensed) = NULL;
- }
- else
- {
- dimensions_type d;
- DIMENSIONS_HEIGHT (d) = height - white_on_top - white_on_bottom;
- DIMENSIONS_WIDTH (d) = width - white_on_left - white_on_right;
- condensed = new_bitmap (d);
-
- for (this_row = 0; this_row < BITMAP_HEIGHT (condensed); this_row++)
- for (this_col = 0; this_col < BITMAP_WIDTH (condensed); this_col++)
- {
- BITMAP_PIXEL (condensed, this_row, this_col)
- = BITMAP_PIXEL (gf_bitmap, this_row + white_on_top,
- this_col + white_on_left);
- }
- GF_CHAR_MIN_ROW (*gf_char) += white_on_bottom;
- GF_CHAR_MAX_ROW (*gf_char) -= white_on_top;
- GF_CHAR_MIN_COL (*gf_char) += white_on_left;
- GF_CHAR_MAX_COL (*gf_char) -= white_on_right;
- }
-
- free_bitmap (&GF_BITMAP (*gf_char));
- GF_BITMAP (*gf_char) = condensed;
- }
- }
-
-
- /* The ``bitmap'' is a sequence of commands that describe it in terms of
- run-length encoding.
-
- GF's row and column numbers are the lower left corner of a pixel.
- GF (0,0) is the Cartesian unit square: 0 <= x (col) <= 1,
- 0 <= y (row) <= 1. Yes, it's <=, not <. What does this mean for
- the maxes and mins? Let's take the height first: if a character has
- min_row = 0 and max_row = 10, we start the ``current'' y at 10,
- (possibly) paint some pixels on that row, ..., and end up with it at
- zero, (possibly) painting some pixels on that row. Thus, there are
- 11 (10 - 0 + 1) rows in which we might paint pixels. Now the width:
- if a character has min_row = 0 and max_row = 4, the current x starts
- at zero, we paint four pixels (let's say), and now the current x is
- four (the max possible), so we cannot paint any more. Thus there are
- four (4 - 0) columns in which we might paint pixels.
-
- Weird, huh? */
-
- static void
- get_character_bitmap (gf_char_type *gf_char)
- {
- /* We expect these to be >= 0, but if the GF file is improper, they
- might turn to be negative. */
- int height, width;
- dimensions_type matrix_dimensions;
- coordinate_type current; /* This will be the GF position. */
- boolean painting_black = false;
-
- current.x = GF_CHAR_MIN_COL (*gf_char);
- current.y = GF_CHAR_MAX_ROW (*gf_char);
-
- width = GF_CHAR_MAX_COL (*gf_char) - GF_CHAR_MIN_COL (*gf_char);
- height = GF_CHAR_MAX_ROW (*gf_char) - GF_CHAR_MIN_ROW (*gf_char) + 1;
-
- /* If the character has zero or negative extent in either dimension,
- it's not going to have a bitmap. (If this happens, the GF file is
- incorrect; but the discrepancy isn't serious, so we may as well not
- bomb out when it happens, especially since PKtoGF has a bug that
- produces such a bounding box when the character is all blank.) */
- if (width <= 0 || height <= 0)
- {
- one_byte b;
- BITMAP_HEIGHT (GF_BITMAP (*gf_char))
- = BITMAP_WIDTH (GF_BITMAP (*gf_char))
- = 0;
- BITMAP_BITS (GF_BITMAP (*gf_char)) = NULL;
-
- /* The next non-NO_OP byte should be EOC. */
- while ((b = GF_GET_BYTE ()) == NO_OP)
- /* do nothing */ ;
- if (b != EOC)
- FATAL1 ("Expected eoc (for a blank character), found %u", b);
-
- return;
- }
-
- DIMENSIONS_HEIGHT (matrix_dimensions) = height;
- DIMENSIONS_WIDTH (matrix_dimensions) = width;
- GF_BITMAP (*gf_char) = new_bitmap (matrix_dimensions);
-
- do
- {
- one_byte c = GF_GET_BYTE ();
-
- if (c == EOC)
- break;
-
- /* No need to test if `PAINT_0 <= c'; it must be, since PAINT_0 is
- zero and `c' is unsigned. */
- if (/* PAINT_0 <= c && */ c <= PAINT3)
- get_paint (¤t, &painting_black, c, gf_char);
-
- else if (SKIP0 <= c && c <= SKIP3)
- get_skip (¤t, &painting_black, c, gf_char);
-
- else if (NEW_ROW_0 <= c && c <= NEW_ROW_164)
- get_new_row (¤t, &painting_black, c, gf_char);
-
- else if (c == NO_OP)
- /* do nothing */ ;
-
- else if ((XXX1 <= c && c <= XXX4) || c == YYY)
- get_specials (GF_FTELL ());
-
- else
- FATAL1 ("Expected paint or skip or new_row, found %u", c);
- }
- while (true);
-
- if (tracing_gf_input)
- puts ("");
- }
-
-
- /* The paint commands come in two varieties -- either with the length
- implicitly part of the command, or where it is specified as a separate
- parameter. */
-
- static void
- get_paint (coordinate_type *current, boolean *painting_black,
- one_byte command, gf_char_type *gf_char)
- {
- unsigned length;
-
- /* No need to test if `PAINT_0 <= command'; it must be, since PAINT_0 is
- zero and `command' is unsigned. */
- if (/* PAINT_0 <= command && */ command <= PAINT_63)
- length = command - PAINT_0;
- else
- {
- switch (command)
- {
- case PAINT1:
- length = GF_GET_BYTE ();
- break;
-
- case PAINT2:
- length = GF_GET_TWO ();
- break;
-
- case PAINT3:
- length = gf_get_three ();
- break;
-
- default:
- FATAL1 ("Expected a paint command, found %u", command);
- }
- }
-
- /* We have to translate from Cartesian to C coordinates. That means the
- x's are the same, but the y's are flipped. */
- if (*painting_black)
- {
- unsigned matrix_y = GF_CHAR_MAX_ROW (*gf_char) - current->y;
-
- if (tracing_gf_input)
- printf ("%u", length);
-
- for (; length != 0; length--)
- {
- unsigned matrix_x = current->x - GF_CHAR_MIN_COL (*gf_char);
-
- BITMAP_PIXEL (GF_BITMAP (*gf_char), matrix_y, matrix_x) = 1;
-
- current->x++;
- }
- }
- else
- {
- current->x += length;
-
- if (tracing_gf_input)
- printf ("(%u)", length);
- }
- *painting_black = !*painting_black;
- }
-
-
- /* Skip commands move down in the GF character, leaving blank rows. */
-
- static void
- get_skip (coordinate_type * current, boolean * painting_black,
- one_byte command, gf_char_type *gf_char)
- {
- unsigned rows_to_skip;
-
- switch (command)
- {
- case SKIP0:
- rows_to_skip = 0;
- break;
-
- case SKIP1:
- rows_to_skip = GF_GET_BYTE ();
- break;
-
- case SKIP2:
- rows_to_skip = GF_GET_TWO ();
- break;
-
- case SKIP3:
- rows_to_skip = gf_get_three ();
- break;
-
- default:
- FATAL1 ("Expected skip command, found %u", command);
- }
-
- current->y -= rows_to_skip + 1;
- current->x = GF_CHAR_MIN_COL (*gf_char);
- *painting_black = false;
-
- if (tracing_gf_input)
- printf ("\nskip %u (y now %d) ", rows_to_skip + 1, current->y);
- }
-
-
- /* `new_row' commands move to the next line down and then over. */
-
- static void
- get_new_row (coordinate_type *current, boolean *painting_black,
- one_byte command, gf_char_type *gf_char)
- {
- current->y--;
- current->x = GF_CHAR_MIN_COL (*gf_char) + command - NEW_ROW_0;
- *painting_black = true;
-
- if (tracing_gf_input)
- printf ("\nnew_row %u (x,y now %d,%d) ", command - NEW_ROW_0,
- current->x, current->y);
- }
-
- /* Instead of building a bitmap, this routine just reads the bytes that
- define the character CHARCODE. If the character doesn't exist, we
- return NULL. */
-
- /* Append the byte `b' to the buffer in `raw_char', followed by (if
- WITH_SIZE_P is true) SIZE, followed SIZE bytes of the input. */
- #define COMMON_APPEND(size, with_size_p) \
- do \
- { \
- append_byte (raw_char, b); \
- if (with_size_p) append_byte (raw_char, size); \
- if (size > 0) append_n_bytes (raw_char, size, get_n_bytes (size, \
- gf_input_file, gf_input_filename)); \
- } \
- while (0)
-
- #define APPEND_BYTES(n) COMMON_APPEND (n, false)
- #define APPEND_VAR_BYTES(n) COMMON_APPEND (n, true)
-
- raw_char_type *
- gf_get_raw_char (one_byte charcode)
- {
- one_byte b; /* Command byte we've just read. */
- gf_char_locator_type char_locator;
- byte_count_type char_pointer;
- byte_count_type old_pos;
- raw_char_type *raw_char;
-
- (void) gf_get_postamble ();
- assert (private_postamble != NULL);
-
- char_locator = GF_CHAR_LOC (*private_postamble, charcode);
- char_pointer = char_locator.char_pointer;
-
- /* If the character doesn't exist in the font, we're done. */
- if (char_pointer == NULL_BYTE_PTR)
- return NULL;
-
- /* Save where we are in the file; we'll restore it when we're done. */
- old_pos = GF_FTELL ();
- GF_FSEEK (char_pointer, SEEK_SET);
-
- raw_char = xmalloc (sizeof (raw_char_type));
- *raw_char = new_raw_gf_char (char_locator);
-
- /* Unfortunately, the GF format doesn't tell us how many bytes long
- the character description is. So, we must decode it enough to
- figure out how much to read. */
-
- /* The first step is the boc: it might be either the one-byte or
- four-byte variant. */
- b = GF_GET_BYTE ();
- if (b == BOC)
- /* The character code, the backpointer (which will probably be wrong
- in the new file, if it exists, but we don't handle non-null
- backpointers anyway), the bounding box. */
- APPEND_BYTES (24);
- else /* b == BOC1 */
- APPEND_BYTES (5);
-
- /* Read the character definition; exit when we get to EOC. */
- while ((b = GF_GET_BYTE ()) != EOC)
- {
- /* First test all the commands that have no parameters. No need to
- test if `PAINT_0 <= b'; it must be, since PAINT_0 is zero and
- `b' is unsigned. */
- if ((/* PAINT_0 <= b && */ b <= PAINT_63)
- || b == SKIP0
- || (NEW_ROW_0 <= b && b <= NEW_ROW_164))
- APPEND_BYTES (0);
-
- /* Now the ones with a one-byte parameter. */
- else if (b == PAINT1 || b == SKIP1)
- APPEND_BYTES (1);
-
- /* A two-byte parameter. */
- else if (b == PAINT2 || b == SKIP2)
- APPEND_BYTES (2);
-
- /* Three-byte. */
- else if (b == PAINT3 || b == SKIP3)
- APPEND_BYTES (3);
-
- /* Four. */
- else if (b == YYY)
- APPEND_BYTES (4);
-
- /* Commands with a variable-size parameter. */
- else if (b == XXX1)
- {
- one_byte size = GF_GET_BYTE ();
- APPEND_VAR_BYTES (size);
- }
-
- else if (b == XXX2)
- {
- two_bytes size = GF_GET_TWO ();
- APPEND_VAR_BYTES (size);
- }
-
- else if (b == XXX3)
- {
- four_bytes size = gf_get_three ();
- APPEND_VAR_BYTES (size);
- }
-
- else if (b == XXX4)
- {
- four_bytes size = GF_GET_FOUR ();
- APPEND_VAR_BYTES (size);
- }
-
- else if (b == NO_OP)
- /* do nothing */;
-
- else
- FATAL1 ("gf_get_raw_char: Bad command byte %u", b);
- }
-
- /* This appends the `eoc'---and now we're done. */
- APPEND_BYTES (0);
-
- GF_FSEEK (old_pos, SEEK_SET);
- return raw_char;
- }
-
-
- /* This macro makes sure the raw character RGC has at least NEEDED
- bytes free. */
- #define ENSURE_AVAILABLE(rgc, needed) \
- while (RAW_CHAR_ALLOCATED (rgc) - RAW_CHAR_USED (rgc) < needed) \
- { \
- RAW_CHAR_ALLOCATED (rgc) *= 2; \
- RAW_CHAR_BYTES (rgc) \
- = xrealloc (RAW_CHAR_BYTES (rgc), RAW_CHAR_ALLOCATED (rgc)); \
- }
-
-
- /* Append the byte B to the end of the RAW_CHAR's buffer. */
-
- static void
- append_byte (raw_char_type *raw_char, one_byte b)
- {
- ENSURE_AVAILABLE (*raw_char, 1);
- RAW_CHAR_UNUSED_START (*raw_char) = b;
- RAW_CHAR_USED (*raw_char)++;
- }
-
-
- /* Append the N bytes of data pointed to by DATA to the end of
- RAW_CHAR's buffer. Free DATA after copying. */
-
- static void
- append_n_bytes (raw_char_type *raw_char, four_bytes n, one_byte *data)
- {
- ENSURE_AVAILABLE (*raw_char, n);
- memcpy (&RAW_CHAR_UNUSED_START (*raw_char), data, n);
- RAW_CHAR_USED (*raw_char) += n;
- free (data);
- }
-
-
- /* Make a new raw character. We have to start off the buffer with some
- nonempty amount of memory, so that the reallocation will have
- something to double. */
-
- static raw_char_type
- new_raw_gf_char (gf_char_locator_type locator)
- {
- raw_char_type c;
-
- RAW_CHAR_ALLOCATED (c) = 1;
- RAW_CHAR_BYTES (c) = xmalloc (RAW_CHAR_ALLOCATED (c));
- RAW_CHAR_USED (c) = 0;
-
- GF_CHARCODE (c) = locator.charcode;
- GF_H_ESCAPEMENT (c) = locator.h_escapement;
- GF_TFM_WIDTH (c) = locator.tfm_width;
- GF_CHAR_BB (c) = GF_FONT_BB (*private_postamble);
-
- /* Since we don't want to interpret the bounding box information in
- the character, we just make our bounding box be the font bounding
- box. Since the only thing a raw character is good for is being
- immediately written back out, this doesn't hurt. (The actual
- bounding box information in the character isn't lost.) */
- return c;
- }
-
- /* Read all specials beginning from the given location, leaving the file
- pointer at the first non-special. We do not save the specials,
- though. */
-
- static void
- get_specials (byte_count_type special_ptr)
- {
- boolean found_special = true;
-
- GF_FSEEK (special_ptr, SEEK_SET);
-
- do
- {
- one_byte c = GF_GET_BYTE ();
-
- switch (c)
- {
- case XXX1:
- (void) gf_get_string (GF_GET_BYTE ());
- break;
-
- case XXX2:
- (void) gf_get_string (GF_GET_TWO ());
- break;
-
- case XXX3:
- (void) gf_get_string (gf_get_three ());
- break;
-
- case YYY:
- (void) GF_GET_FOUR ();
- break;
-
- default:
- found_special = false;
- GF_FSEEK (-1, SEEK_CUR);
- }
- }
- while (found_special);
- }
-
-
- static string
- gf_get_string (unsigned length)
- {
- string s;
-
- if (length == 0) return "";
-
- s = get_n_bytes (length, gf_input_file, gf_input_filename);
- s = xrealloc (s, length + 1);
- s[length] = 0;
- return s;
- }
-
-
- /* C does not provide an obvious type for a 24-bit quantity, so we
- return a 32-bit one. */
-
- static four_bytes
- gf_get_three ()
- {
- four_bytes v = get_two (gf_input_file, gf_input_filename) << 8;
- v |= get_byte (gf_input_file, gf_input_filename);
-
- return v;
- }
-